<?php

namespace App\Console\Commands;

use App\Models\AutoMarkingRecord;
use App\Services\GradioService;
use App\Services\OcrService;
use Illuminate\Console\Command;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use \Exception;

class AutoMarkingCommand extends Command
{
    /**
     * 命令名称
     *
     * @var string
     */
    protected $signature = 'marking:auto-mark {--subjective-id=2vpqpsob3z7k : 主观题ID} {--max-count=1 : 最大执行次数}';

    /**
     * 命令描述
     *
     * @var string
     */
    protected $description = '自动评卷命令 - 支持循环执行，获取题目、OCR识别、评分并提交结果';

    /**
     * OCR服务
     *
     * @var OcrService
     */
    protected $ocrService;

    /**
     * 当前处理的记录
     *
     * @var AutoMarkingRecord
     */
    protected $currentRecord;

    protected $question = '阅读下面的文字，任选一个任务、按照要求写作。
春节期间，DeepScek 创始人梁文峰、《哪吒》电影导演饺子，分别在科技与电影领域因热爱与创新收获成就。他们以热爱为动力、创新为利刃，或推动科技进步，或传播文化力量，让个人理想在时代浪潮中绽放熠烟光彩。在你的生活中，是否也有因为热爱而不断前行，因为创新而收获成长的经历呢?
请从以下两个任务中任选一个，完成作文。来是因为血拼博
任务一:请以“因为热爱，所以____”为标题，写一篇记叙文。
任务二:请以“梦想源于____”为标题，写一篇演讲稿。
要求:(1)请将题目补充完整。(2)内容具体充实，有真情实感。(3)文中不得出现真实姓名。(4)不少于 500字。';

    /**
     * 请求头信息
     *
     * @var array
     */
    protected $headers = [
        'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
        'Referer' => 'https://www.igrade.cn/emarking/marking/2uygdximn3ls/mark/2vpqpsob3z7k',
        'Accept' => 'application/json',
        'Accept-Language' => 'zh-CN,zh;q=0.9',
    ];

    /**
     * 构造函数
     */
    public function __construct()
    {
        parent::__construct();
        $this->ocrService = new GradioService();
    }

    /**
     * 执行命令
     */
    public function handle()
    {
        $subjectiveId = $this->option('subjective-id');
        $maxCount = (int) $this->option('max-count');
        $authentication = config('services.igrade.authentication');

        if (empty($authentication)) {
            $this->error('请在 config/services.php 中配置 igrade.authentication 参数');
            return 1;
        }

        $this->info('开始自动评卷流程...');
        $this->info('主观题ID: ' . $subjectiveId);
        $this->info('最大执行次数: ' . $maxCount);

        // 0. 检查登录状态
        if (!$this->checkLoginStatus($authentication)) {
            $this->error('用户未登录或登录状态已过期');
            return 1;
        }

        $this->info('用户登录状态验证成功');

        $successCount = 0;
        $failCount = 0;

        for ($i = 1; $i <= $maxCount; $i++) {
            // 监控内存使用情况
            $memoryUsage = memory_get_usage(true);
            $memoryPeak = memory_get_peak_usage(true);
            $this->info("\n=== 开始第 {$i} 次评卷 ====");
            $this->info("当前内存使用: " . round($memoryUsage / 1024 / 1024, 2) . "MB, 峰值: " . round($memoryPeak / 1024 / 1024, 2) . "MB");

            $result = $this->processOneMarking($subjectiveId, $authentication, $i);

            if ($result === 0) {
                $successCount++;
                $this->info("第 {$i} 次评卷成功");
            } else {
                $failCount++;
                $this->error("第 {$i} 次评卷失败");
            }

            // 每次循环后强制垃圾回收
            gc_collect_cycles();
            
            // 清理HTTP连接池（如果Laravel版本支持）
            if (method_exists(Http::class, 'pool')) {
                Http::pool(function () {});
            }

            // 如果不是最后一次，稍作延迟
            if ($i < $maxCount) {
                $this->info('等待 2 秒后继续下一次评卷...');
                sleep(2);
            }
            
            // 检查内存使用，如果超过100MB发出警告
            $currentMemory = memory_get_usage(true);
            if ($currentMemory > 100 * 1024 * 1024) {
                $this->warn("内存使用过高: " . round($currentMemory / 1024 / 1024, 2) . "MB");
            }
        }

        $this->info("\n=== 评卷完成统计 ===");
        $this->info("总执行次数: {$maxCount}");
        $this->info("成功次数: {$successCount}");
        $this->info("失败次数: {$failCount}");

        return $failCount > 0 ? 1 : 0;
    }

    /**
     * 处理单次评卷
     *
     * @param string $subjectiveId
     * @param string $authentication
     * @param int $attemptNumber
     * @return int
     */
    protected function processOneMarking($subjectiveId, $authentication, $attemptNumber = 1)
    {
        // 在每次处理开始前强制垃圾回收
        gc_collect_cycles();
        
        try {
            // 创建初始记录
            $this->currentRecord = AutoMarkingRecord::create([
                'subjective_id' => $subjectiveId,
                'processed_at' => now(),
                'attempt_number' => $attemptNumber,
            ]);

            // 1. 获取题目信息
            $questionData = $this->fetchQuestion($subjectiveId, $authentication);
//            $questionData = [
//                "groupId" => "90ab30da-1f7b-4567-9d36-702bdee08afe",
//                "isTrailMarking" => false,
//                "subjectiveId" => "2vpqpsob3z7k",
//                "subjectiveItemId" => "2vpvss8gglcc",
//                "markStatus" => 21,
//                "readTime" => "2025-07-04 09:52:07",
//                "no" => 115,
//                "imgUrl" => "https://img3.igrade.cn/sure/subpage/2uygdximn3ls/379227421821550592/2vpqpsob3z7k_1751512463853.jpg?t=1751616670953",
//                "secretNum" => "WJTY6534",
//                "type" => 0
//            ];
            if (!$questionData) {
                $this->error("第 {$attemptNumber} 次评卷：获取题目信息失败");
                $this->currentRecord->update(['error_message' => '获取题目信息失败']);
                return 1;
            }

            // 更新记录中的题目信息
            $this->currentRecord->update([
                'subjective_item_id' => $questionData['subjectiveItemId'] ?? null,
                'group_id' => $questionData['groupId'] ?? null,
                'question_no' => $questionData['no'] ?? null,
                'secret_num' => $questionData['secretNum'] ?? null,
                'image_url' => $questionData['imgUrl'] ?? null,
                'question_data' => $questionData,
            ]);

            $this->info("第 {$attemptNumber} 次评卷：成功获取题目信息");
            $this->info('题目编号: ' . ($questionData['no'] ?? 'N/A'));
            $this->info('图片URL: ' . ($questionData['imgUrl'] ?? 'N/A'));

            // 2. 下载并OCR识别图片
            $ocrResult = $this->processImageOcr($questionData['imgUrl']);
            if (!$ocrResult) {
                $this->error("第 {$attemptNumber} 次评卷：OCR识别失败");
                $this->currentRecord->update(['error_message' => 'OCR识别失败']);
                return 1;
            }

            // 过滤掉匹配 "A?\d+字" 模式的行
            $filteredOcrResult = array_filter($ocrResult, function($line) {
                return !preg_match('/^[A-Z]?\d+[字号学季E享]?$/u', $line);
            });

            $textContent = implode("\n", $filteredOcrResult);
            $line_count = count($filteredOcrResult);
            $text_length = mb_strlen(implode($filteredOcrResult));

            // 更新OCR结果到记录
            $this->currentRecord->update([
                'ocr_content_list' => array_values($filteredOcrResult),
                'ocr_full_text' => $textContent,
                'word_count' => $text_length,
                'line_count' => $line_count,
            ]);

            $this->info("第 {$attemptNumber} 次评卷：OCR识别成功");
            $this->info('识别内容: ' . mb_substr($textContent, 0, 200) . '...');
            $this->info('原始识别到 ' . count($ocrResult) . ' 行文本，过滤后剩余 ' . $line_count . ' 行文本');
            $this->info('原始识别到 ' . mb_strlen(implode($ocrResult)) . ' 个文本，过滤后剩余 ' . $text_length . ' 个文本');
//            file_put_contents(uniqid('x-').'.txt', $textContent);
//            dump($textContent);

            // 3. 评分
            $scoreRes_list = $this->calculateScore($filteredOcrResult);
//            dump($scoreRes_list);

            $aiScores = [];
            foreach ($scoreRes_list as $ai_model => $scoreRes) {
                if (isset($scoreRes['res']['总分'])) {
                    $aiScores[$ai_model] = $scoreRes['res']['总分'];
                }
            }

            // 根据分数分布选择最终分数
            $scores = collect($aiScores);
            $allScoresAbove40 = $scores->every(function($score) { return $score >= 40; });
            $allScoresBelow40 = $scores->every(function($score) { return $score < 40; });

            if ($allScoresAbove40) {
                // 所有分数都大于等于40，取最小值
                $finalScore = $scores->min();
                $this->info('所有AI评分都≥40，取最小值: ' . $finalScore);
//            } elseif ($allScoresBelow40) {
//                // 所有分数都小于40，取最大值
//                $finalScore = $scores->max();
//                $this->info('所有AI评分都<40，取最大值: ' . $finalScore);
            } else {
                // 其他情况取平均值
                $finalScore = round($scores->avg());
                $this->info('AI评分有高有低，取平均值: ' . $finalScore);
            }

            $averageScore = $finalScore;

            // 微调分数
            $adjustedScore = $averageScore;
            if ($adjustedScore < 25) {
                if ($text_length >= 200) $adjustedScore = 25;
                else if ($text_length >= 150) $adjustedScore = 20;
                else if ($text_length >= 100) $adjustedScore = 15;
                else if ($text_length >= 50) $adjustedScore = 10;
                else $adjustedScore = 5;
            } else if ($adjustedScore > 48) {
                $adjustedScore = 48;
            } else if ($adjustedScore > 35) {
                if ($text_length < 400) {
                    if ($text_length >= 350) $adjustedScore = 30;
                    else if ($text_length >= 300) $adjustedScore = 28;
                    else if ($text_length >= 200) $adjustedScore = 25;
                    else if ($text_length >= 150) $adjustedScore = 20;
                    else if ($text_length >= 100) $adjustedScore = 15;
                    else if ($text_length >= 50) $adjustedScore = 10;
                    else $adjustedScore = 5;
                }
            }
            $this->info('微调后得分: ' . $adjustedScore);

            // 更新AI评分结果到记录
            $this->currentRecord->update([
                'ai_score_results' => $scoreRes_list,
                'average_score' => $averageScore,
                'adjusted_score' => $adjustedScore,
            ]);

            // 4. 提交评分结果
            $submitResult = $this->submitScore(
                $questionData['subjectiveId'],
                $questionData['subjectiveItemId'],
                $adjustedScore,
                $authentication
            );

            // 更新提交结果到记录
            $this->currentRecord->update([
                'submitted_score' => $adjustedScore,
                'submit_result' => $submitResult,
                'is_submitted' => $submitResult !== false,
            ]);

            // 清理大变量以释放内存
            unset($questionData, $ocrResult, $filteredOcrResult, $textContent, $scoreRes_list, $aiScores, $scores);
            $this->currentRecord = null;
            
            if ($submitResult) {
                $this->info("第 {$attemptNumber} 次评卷：评分提交成功");
                return 0;
            } else {
                $this->error("第 {$attemptNumber} 次评卷：评分提交失败");
                return 1;
            }

        } catch (\Exception $e) {
            $this->error("第 {$attemptNumber} 次评卷过程中发生异常: " . $e->getMessage());

            // 记录异常信息
            if ($this->currentRecord) {
                $this->currentRecord->update([
                    'error_message' => $e->getMessage(),
                ]);
            }

            Log::error('自动评卷异常', [
                'subjective_id' => $subjectiveId,
                'attempt_number' => $attemptNumber,
                'record_id' => $this->currentRecord?->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            // 清理资源
            $this->currentRecord = null;
            gc_collect_cycles();
            
            return 1;
        } finally {
            // 确保在方法结束时清理资源
            $this->currentRecord = null;
            gc_collect_cycles();
        }
    }

    /**
     * 检查登录状态
     *
     * @param string $authentication
     * @return bool
     */
    protected function checkLoginStatus($authentication)
    {
        try {
            $timestamp = 1751593569371; // 毫秒时间戳
            $url = "https://www.igrade.cn/api2/user/user/Info?_t_={$timestamp}";

            $headers = array_merge($this->headers, [
                'Authentication' => $authentication,
            ]);

            $response = Http::withHeaders($headers)->get($url);

            if ($response->successful()) {
                $data = $response->json();

                if (isset($data['code']) && $data['code'] === 0 && isset($data['data'])) {
                    // 输出用户信息
                    $userInfo = $data['data'];
                    $this->info('登录用户: ' . ($userInfo['realName'] ?? $userInfo['userName'] ?? 'N/A'));
                    $this->info('学校: ' . ($userInfo['schoolName'] ?? 'N/A'));
                    return true;
                } else {
                    $this->error('登录状态检查失败: ' . ($data['message'] ?? '未知错误'));
                    return false;
                }
            } else {
                $this->error('登录状态检查请求失败: HTTP ' . $response->status());
                return false;
            }
        } catch (\Exception $e) {
            $this->error('登录状态检查异常: ' . $e->getMessage());
            Log::error('登录状态检查异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return false;
        }
    }

    /**
     * 获取题目信息
     *
     * @param string $subjectiveId
     * @param string $authentication
     * @return array|null
     */
    protected function fetchQuestion($subjectiveId, $authentication)
    {
        $timestamp = time() * 1000; // 毫秒时间戳
        $url = "https://www.igrade.cn/api2/mark/mark?subjectiveId={$subjectiveId}&_t_={$timestamp}";

        $headers = array_merge($this->headers, [
            'Authentication' => $authentication,
        ]);

        $response = Http::withHeaders($headers)->get($url);

        if ($response->successful()) {
            $data = $response->json();

            if (isset($data['code']) && $data['code'] === 0 && isset($data['data'])) {
                return $data['data'];
            } else {
                $this->error('API返回错误: ' . ($data['message'] ?? '未知错误'));
                return null;
            }
        } else {
            $this->error('API请求失败: HTTP ' . $response->status());
            return null;
        }
    }

    /**
     * 处理图片OCR识别
     *
     * @param string $imageUrl
     * @return string|null
     */
    protected function processImageOcr($imageUrl, $max_times = 5)
    {
        $now_times = 1;
        while ($now_times++ <= $max_times) {
            try {
                // 使用图片预处理功能进行OCR识别
                // 启用预处理：将图片竖着对半切开，第一个图去掉顶部50px，第二个图去掉顶部300px
                $result = $this->recognizeTextWithPreprocess($imageUrl);

                return $result;
            } catch (\Exception $e) {
                $this->error('OCR处理异常: ' . $e->getMessage());
                Log::error('OCR处理异常', [
                    'image_url' => $imageUrl,
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString()
                ]);
            }
            sleep(5);
        }
        return null;
    }

    /**
     * 计算分数
     * 这里是一个简单的评分逻辑，可以根据实际需求调整
     *
     * @param array $ocrTexts
     * @return array
     */
    protected function calculateScore($ocrTexts)
    {
        // 简单的评分逻辑示例
        $textContent = implode("\n", $ocrTexts);

        $line_count = count($ocrTexts);
        $font_count = mb_strlen(implode($ocrTexts));

        $data = [
            format_field_name('line_count') => $line_count,
            format_field_name('font_count') => $font_count,
            format_field_name('input') => $textContent,
            format_field_name('question') => $this->question,
        ];
        $content = strtr(score_composition, $data);
        
        // 清理data变量
        unset($data, $textContent);
        
        $fields = [
            "总分", "字数统计", "字数档次", "评分档次", "基础分", "加分", "扣分", "扣分详情", "加分项", "各项评分", "主要优点", "主要问题", "改进建议", "总体评价",
        ];
        $check_func = function ($res) use ($fields) {
            if ($res && ($res['answer'] ?? '')) {
                $res = format_json($res['answer']);
                if ($res) {
                    if (isset($res['error']) || count(array_intersect($fields, array_keys($res))) == count($fields)) {
                        return $res;
                    }
                }
            }
            return false;
        };
        
        // 默认模型
        $ai_models = [
            'ms_api/deepseek-ai/DeepSeek-V3',
            'ms_api/Qwen/Qwen3-32B/think',
            'ms_api/Qwen/Qwen3-235B-A22B/think',
            'deepseek_api/deepseek-chat',
            'ms_api/Qwen/Qwen3-32B/not_think',
            'ms_api/Qwen/Qwen3-235B-A22B/not_think',
            'ms_api/deepseek-ai/DeepSeek-R1-0528',
            'deepseek_api/deepseek-reasoner',
        ];
        
        $output = [];
        foreach ($ai_models as $ai_model) {
            $res = auto_chat_bat($content, $ai_model, $check_func);
            if ($res) {
                $this->info($ai_model.' 评分结果: ' . $res['res']['总分']);
                $output[$ai_model] = $res;
                if (count($output) >= 3) {
                    break;
                }
            } else {
                $this->info($ai_model.' 评分失败');
            }
            
            // 清理单次循环的变量
            unset($res);
            
            // 每处理一个模型后进行垃圾回收
            if (count($output) % 2 === 0) {
                gc_collect_cycles();
            }
        }
        
        // 清理局部变量
        unset($content, $fields, $check_func, $ai_models);

        return $output;
    }

    /**
     * 提交评分结果
     *
     * @param string $subjectiveId
     * @param string $subjectiveItemId
     * @param int $score
     * @param string $authentication
     * @return bool
     */
    protected function submitScore($subjectiveId, $subjectiveItemId, $score, $authentication)
    {
        $url = 'https://www.igrade.cn/api2/mark/mark/submit';

        $headers = array_merge($this->headers, [
            'Authentication' => $authentication,
            'Content-Type' => 'application/json',
        ]);

        $payload = [
            'subjectiveId' => $subjectiveId,
            'subjectiveItemId' => $subjectiveItemId,
            'score' => $score,
            'subScore' => "20={$score}",
            'commentJson' => null
        ];

        $response = Http::withHeaders($headers)->post($url, $payload);

        if ($response->successful()) {
            $data = $response->json();

            if (isset($data['code']) && $data['code'] === 0) {
                return true;
            } else {
                $this->error('提交评分失败: ' . ($data['message'] ?? '未知错误'));
                return false;
            }
        } else {
            $this->error('提交评分请求失败: HTTP ' . $response->status());
            return false;
        }
    }

    protected function downloadImageToTemp($image)
    {
        if ($image instanceof UploadedFile) {
            $tempPath = tempnam(sys_get_temp_dir(), 'ocr_download_') . '.' . $image->getClientOriginalExtension();
            $image->move(dirname($tempPath), basename($tempPath));
            return $tempPath;
        } elseif (is_string($image)) {
            if (filter_var($image, FILTER_VALIDATE_URL)) {
                // 下载网络图片
                $response = Http::timeout(30)->get($image);
                if (!$response->successful()) {
                    throw new Exception('下载图片失败: HTTP ' . $response->status());
                }

                $tempPath = tempnam(sys_get_temp_dir(), 'ocr_download_') . '.jpg';
                
                // 获取响应体并立即释放响应对象
                $imageData = $response->body();
                unset($response); // 立即释放HTTP响应对象
                
                file_put_contents($tempPath, $imageData);
                unset($imageData); // 释放图片数据
                
                return $tempPath;
            } else {
                // 本地文件路径
                if (!file_exists($image)) {
                    throw new Exception('图片文件不存在: ' . $image);
                }
                return $image;
            }
        } else {
            throw new Exception('不支持的图片类型');
        }
    }

    protected function recognizeTextWithPreprocess($image)
    {
        $processedImages = [];
        $results = [];
        
        try {
            // 下载并预处理图片
            $processedImages = $this->preprocessImage($image);

            foreach ($processedImages as $index => $processedImage) {
                try {
                    // 提交OCR任务
                    $result = $this->ocrService->recognizeImage($processedImage);
                    if (isset($result['result'][1]['rec_texts'])) {
                        $results = array_merge($results, $result['result'][1]['rec_texts']);
                    }
                    
                    // 立即清理OCR结果变量
                    unset($result);
                    
                } catch (Exception $e) {
                    $this->error(exception_to_string($e));
                    Log::error("OCR识别第{$index}部分失败", [
                        'error' => $e->getMessage()
                    ]);
                    // 继续处理其他部分，但不返回false，而是继续
                }
            }
            
            return $results;
            
        } finally {
            // 确保清理所有临时文件
            foreach ($processedImages as $processedImage) {
                if (file_exists($processedImage)) {
                    unlink($processedImage);
                }
            }
            unset($processedImages);
        }
    }

    /**
     * 图片预处理：竖着对半切开，并去掉指定顶部像素
     *
     * @param string|UploadedFile $image
     * @return array 处理后的图片路径数组
     * @throws Exception
     */
    protected function preprocessImage($image)
    {
        $tempImagePath = null;
        $sourceImage = null;
        $processedImages = [];
        
        try {
            // 下载图片到临时文件
            $tempImagePath = $this->downloadImageToTemp($image);

            // 获取图片信息
            $imageInfo = getimagesize($tempImagePath);
            if (!$imageInfo) {
                throw new Exception('无法获取图片信息');
            }

            $width = $imageInfo[0];
            $height = $imageInfo[1];
            $type = $imageInfo[2];
            
            // 释放imageInfo变量
            unset($imageInfo);

            // 创建图片资源
            switch ($type) {
                case IMAGETYPE_JPEG:
                    $sourceImage = imagecreatefromjpeg($tempImagePath);
                    break;
                case IMAGETYPE_PNG:
                    $sourceImage = imagecreatefrompng($tempImagePath);
                    break;
                case IMAGETYPE_GIF:
                    $sourceImage = imagecreatefromgif($tempImagePath);
                    break;
                default:
                    throw new Exception('不支持的图片格式');
            }

            if (!$sourceImage) {
                throw new Exception('无法创建图片资源');
            }

            $halfWidth = intval($width / 2);

            // 第一部分：左半部分，去掉顶部50px
            $cropTop1 = 55;
            $cropHeight1 = $height - $cropTop1;
            if ($cropHeight1 > 0) {
                $image1 = imagecreatetruecolor($halfWidth, $cropHeight1);
                if ($image1) {
                    imagecopy($image1, $sourceImage, 0, 0, 0, $cropTop1, $halfWidth, $cropHeight1);
                    
                    $tempPath1 = tempnam(sys_get_temp_dir(), 'ocr_part1_') . '.jpg';
                    imagejpeg($image1, $tempPath1, 90);
                    imagedestroy($image1);
                    $processedImages[] = $tempPath1;
                }
            }

            // 第二部分：右半部分，去掉顶部300px
            $cropTop2 = 280;
            $cropHeight2 = $height - $cropTop2;
            if ($cropHeight2 > 0) {
                $image2 = imagecreatetruecolor($halfWidth, $cropHeight2);
                if ($image2) {
                    imagecopy($image2, $sourceImage, 0, 0, $halfWidth, $cropTop2, $halfWidth, $cropHeight2);
                    
                    $tempPath2 = tempnam(sys_get_temp_dir(), 'ocr_part2_') . '.jpg';
                    imagejpeg($image2, $tempPath2, 90);
                    imagedestroy($image2);
                    $processedImages[] = $tempPath2;
                }
            }

            return $processedImages;

        } catch (Exception $e) {
            // 清理已创建的处理图片
            foreach ($processedImages as $processedImage) {
                if (file_exists($processedImage)) {
                    unlink($processedImage);
                }
            }
            throw $e;
        } finally {
            // 清理资源
            if ($sourceImage) {
                imagedestroy($sourceImage);
            }
            if ($tempImagePath && file_exists($tempImagePath)) {
                unlink($tempImagePath);
            }
        }
    }

    public function info($string, $verbosity = null)
    {
        $string = date('[H:i:s] ').$string;
        parent::info($string, $verbosity);
    }
}
